package insight.springia5.chapter08.amqp.consumer;

import insight.springia5.chapter06.domain.Order;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;

/**
 * 与 JMS 类似 有拉取和推送
 * 
 * 拉取: 使用 RabbitTemplate
 * 推送: 使用 @RabbitListener 监听
 * 
 * 不同的是, 接收消息无需关心 exchange & key
 * 只需要关注队列
 * 除此之外, 还多了一个 timeout 默认 0ms 可在配置文件设置
 * 如果没有消息则返回 null
 * 
 * @author insight
 * @since 2021/7/22
 */
@Service
public class OrderMsgConsumerImpl implements OrderMsgConsumer {
    private RabbitTemplate rabbitTemplate;
    private MessageConverter converter;

    @Autowired
    public OrderMsgConsumerImpl(RabbitTemplate rabbitTemplate,
                                MessageConverter converter) {
        this.rabbitTemplate = rabbitTemplate;
        this.converter = converter;
    }

    /**
     * 使用 receive 注意处理消息为空的情况
     */
    /*@Override
    public Order receive() {
        Message msg = rabbitTemplate.receive(
                "tacocloud.orders");
        return msg != null ? (Order) converter.fromMessage(msg) : null;
        
        *//*Optional<Message> o = Optional.ofNullable(rabbitTemplate.receive(
                "tacocloud.orders"));
        return (Order) o.map(msg -> converter.fromMessage(msg))
                .orElseGet(Order::new);*//*
    }*/

    /**
     * 使用 receiveAndConvert
     */
    /*@Override
    public Order receive() {
        return (Order) rabbitTemplate.receiveAndConvert("tacocloud.orders");
    }*/

    /**
     * 使用第三个参数避免强转
     * 使用 ParameterizedTypeReference convert 必须要实现 SmartMessageConverter
     * Jackson2JsonMessageConverter 是唯一一个可选的内置实现
     * 
     * 关于强制和使用 ParameterizedTypeReference 哪个更好 不确定
     */
    @Override
    public Order receive() {
        return rabbitTemplate.receiveAndConvert("tacocloud.orders",
                new ParameterizedTypeReference<Order>(){}
        );
    }
}